﻿// ////////////////////////////////////////////////////////////////////////////
// 
// SWE Case Tool
// 
// Solution:	CaseTool
// Project:		4. MethodCocomo
// Filename:	FrmCocomo.cs
// 
// File Created:	17:06 31.05.2013 
// Last Changed:	18:11 05.06.2013
// 
// ////////////////////////////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using SWE.CaseTool.Methods.Controls;

namespace SWE.CaseTool.Methods
{
	/// <summary>
	/// Method GUI for the Cocomo Method. Offers input for the cocomo factor weights and displays the
	/// result.
	/// </summary>
	[MethodGUI(typeof (CocomoMethod))]
	public partial class FrmCocomo : Form, IChanged, IMethodGUI
	{
		/// <summary>
		/// The cocomo method which this gui will work on
		/// </summary>
		private CocomoMethod cocomoMethod = new CocomoMethod();

		/// <summary>
		/// Initializes a new instance of the <see cref="FrmCocomo" /> class.
		/// </summary>
		public FrmCocomo()
		{
			InitializeComponent();

			cbSize.Items.AddRange(Enum.GetValues(typeof (ProjectSize)).Cast<object>().ToArray());
			Changed += (sender, args) => Recalculate();
		}

		/// <summary>
		/// Recalculates this the estimated project time.
		/// </summary>
		private void Recalculate()
		{
			try
			{
				tbResult.Text = string.Format("{0:0.##} Tage", cocomoMethod.Calculate());
				lblResult.Text = string.Format("COCOMO berechnet: {0}", tbResult.Text);
			}
			catch (Exception ex)
			{
				lblResult.Text = string.Format("ERROR: {0}", ex.Message.ToUpper());
			}
		}

		/// <summary>
		/// Handles the ValueChanged event of the numKDSI control. DataBinding: Takes the new value and
		/// writes it back to the data field in the cocomo method. Recalculates the results, after changing
		/// the data.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">
		/// The <see cref="EventArgs" /> instance containing the event data.
		/// </param>
		private void NumKDSIValueChanged(object sender, EventArgs e)
		{
			cocomoMethod.KDSI = (double) numKDSI.Value;
			Recalculate();
		}

		/// <summary>
		/// Handles the SelectedIndexChanged event of the cbSize control. DataBinding: Takes the new value and
		/// writes it back to the data field in the cocomo method. Recalculates the results, after changing
		/// the data.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">
		/// The <see cref="EventArgs" /> instance containing the event data.
		/// </param>
		private void CbSizeSelectedIndexChanged(object sender, EventArgs e)
		{
			cocomoMethod.Size = (ProjectSize) cbSize.SelectedItem;
			Recalculate();
		}

		/// <summary>
		/// Handles the Click event of the btnReset control. DataBinding: Takes the new value and
		/// writes it back to the data field in the cocomo method. Recalculates the results, after changing
		/// the data.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">
		/// The <see cref="EventArgs" /> instance containing the event data.
		/// </param>
		private void BtnResetClick(object sender, EventArgs e)
		{
			var tmp = new CocomoMethod();
			tmp.CopyTo(cocomoMethod);

			SetMethod(cocomoMethod);
		}

		/// <summary>
		/// Sets the method which should be displayed in the gui. The method factory creates or loads a method
		/// and hands it, while creating the window, over to the window using this method.
		/// </summary>
		/// <param name="loadedMethod">The loaded method.</param>
		/// <exception cref="System.ArgumentException">
		/// Corrupt data. Unable to load the given percentage method
		/// data.
		/// </exception>
		public void SetMethod(IMethod loadedMethod)
		{
			cocomoMethod = loadedMethod as CocomoMethod;
			if (cocomoMethod == null)
			{
				throw new ArgumentException("Corrupt data. Unable to load the given percentage method data.");
			}

			cbSize.SelectedItem = cocomoMethod.Size;
			numKDSI.Value = (decimal) cocomoMethod.KDSI;

			var tmp = new Dictionary<string, List<CocomoFactor>>();
			foreach (var x in cocomoMethod.Factors)
			{
				if (!tmp.ContainsKey(x.Category))
				{
					tmp.Add(x.Category, new List<CocomoFactor>());
				}

				tmp[x.Category].Add(x);
			}

			foreach (var keyValPair in tmp)
			{
				var category = tmp[keyValPair.Key];
				var group = new CtrlCocomoFactorGroup
					{
						Text = keyValPair.Key,
						AutoSize = true
					};

				foreach (var value in category)
				{
					group.AddControl(new CtrlCocomoFactor(value)
						{
							Anchor = AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Left,
							Width = @group.ClientSize.Width
						});
				}

				grpFactors.AddControl(group);
			}

			grpFactors.Size = new Size(539, 560);
		}

		/// <summary>
		/// Returns the mehtods which is displayed in this gui.
		/// </summary>
		/// <returns>
		/// the method.
		/// </returns>
		public IMethod GetMethod() { return cocomoMethod; }

		/// <summary>
		/// Gets or sets the changed event handler for notifiing the parent of changes in it's child objects.
		/// E.G. a change in a
		/// subcontrol which modifies a parameter, a recalcutation of the whole project is needed. The child
		/// control then uses the Changed-Method of it's parent to tell him that something has changed
		/// </summary>
		/// <value>
		/// The changed event handler.
		/// </value>
		public ChangedEventHandler Changed { get; set; }
	}
}